package kv

import (
	"context"
	"time"
)

type RetType int

const (
	Success   RetType = 1
	Fail      RetType = 0
	NotExists RetType = -1
)

type Storage interface {
	NewPipeline(ctx context.Context) Pipeline
	Incr(ctx context.Context, key string) (int64, error)
	IncrBy(ctx context.Context, key string, value int64) (int64, error)
	DecrBy(ctx context.Context, key string, value int64) (int64, error)

	Set(ctx context.Context, key, value string, expiration time.Duration) (string, error)
	SetNX(ctx context.Context, key, value string, expiration time.Duration) (ok bool, err error)
	Get(ctx context.Context, key string) (string, error) // return redis.Nil if key not exists
	Expire(ctx context.Context, key string, expiration time.Duration) (bool, error)
	Exists(ctx context.Context, keys ...string) (int64, error)
	Del(ctx context.Context, key string) error

	CompareAndSet(ctx context.Context, key, oldValue, newValue string, expiration time.Duration) (RetType, error)
	CompareAndDelete(ctx context.Context, key, value string) (RetType, error)

	RPush(ctx context.Context, key string, value []string) (int64, error)
	LRange(ctx context.Context, key string, start, stop int64) ([]string, error)
	LPop(ctx context.Context, key string) (string, error)
	LTrim(ctx context.Context, key string, start, stop int64) error
	LLen(ctx context.Context, key string) (int64, error)

	HSet(ctx context.Context, key, field, value string) (bool, error)
	HDel(ctx context.Context, key string, field ...string) (int64, error)
	HKeys(ctx context.Context, key string) ([]string, error)
	HGetSet(ctx context.Context, key, field string, value interface{}) (string, error)
	HGetAll(ctx context.Context, key string) (map[string]string, error)
	HMSet(ctx context.Context, key string, fields map[string]interface{}) (string, error)
	HScan(ctx context.Context, key, match string, cursor uint64, count int64) ([]string, uint64, error)
	HGet(ctx context.Context, key, field string) (string, error)
	HLen(ctx context.Context, key string) (int64, error)

	ZRem(ctx context.Context, key string, members ...interface{}) error
	ZAdd(ctx context.Context, key string, members ...ZMember) error
	ZRangeWithScore(ctx context.Context, key string, start, stop int64) ([]ZMember, error)
	ZScore(ctx context.Context, key, member string) (float64, error)
}

type Cmder interface {
	Args() []interface{}
	Name() string
	Err() error
}

type Pipeline interface {
	Incr(key string)
	IncrBy(key string, value int64)
	DecrBy(key string, value int64)
	Set(key, value string, expiration time.Duration)
	SetNX(key, value string, expiration time.Duration)
	Get(key string)
	Del(key ...string)
	RPush(key string, value []string)
	Expire(key string, expiration time.Duration)
	HSet(key, field, value string)
	HMSet(key string, fields map[string]interface{})
	HDel(key, field string)
	Exec() ([]Cmder, error)
}

type ZMember struct {
	Member interface{}
	Score  float64
}
